package com.john.booter.authority;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import com.john.booter.annotation.Module;
import com.john.booter.annotation.OptionName;
import com.john.booter.annotation.SubModuleName;
import com.john.booter.domain.entity.Option;
import com.john.booter.module.option.service.OptionService;

/**
 * 权限URL扫描类
 * @author weny
 */
public class AuthorityScanner {
	protected Logger logger = LoggerFactory.getLogger(getClass());
	
	private ApplicationContext appContext;
	private OptionService optionService;
	
	public AuthorityScanner(ApplicationContext context) {
		super();
		this.appContext = context;
		this.optionService = (OptionService) context.getBean(OptionService.class);
	}

	/**
	 * 扫描注解，并保存到数据库
	 */
	public void scan() {
		logger.debug(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>URL扫描开始<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
		
		// 一级Option
		List<Option> first = getFirstLevelOption();
		// 二、三级级Option
		List<Option> all = getSecondAndThirdLevelOption();
		all.addAll(first);
		
		// 批量插入或新增
		optionService.batchMerge(all);
		
		logger.debug(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>URL扫描结束<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
	}

	/**
	 * 三级Option
	 * @param classMethodMap
	 * @return 
	 */
	private List<Option> getThirdLevelOption(Map<Option, Method[]> classMethodMap) {
		// 三级
		List<Option> thirdList = new ArrayList<Option>();
		for (Map.Entry<Option, Method[]> entry : classMethodMap.entrySet()) {  
			Option pOption = entry.getKey();
		    Method[] ms = entry.getValue();
		    if(ArrayUtils.isEmpty(ms)) {
		    	continue;
		    }
		    for (Method m : ms) {
		    	if (!m.isAnnotationPresent(RequestMapping.class)) {
					continue;
				}
				if (!m.isAnnotationPresent(OptionName.class)) {
					String _method = m.getName() + "()";
					logger.warn("注意:" + _method + "没加上@Menu()");
					continue;
				}
				
				RequestMapping rm = m.getAnnotation(RequestMapping.class);
				OptionName on = m.getAnnotation(OptionName.class);
				
				String name = on.value();
				String parentCode = pOption.getCode();
				Integer sort = on.sort();
				Integer level = 3;
				String methodUrl = rm.value()[0];
				String code = parentCode.concat("-").concat(methodUrl.replaceFirst("/", ""));
				String url = pOption.getUrl().concat(methodUrl);
				String type = "METHOD";
				
				Option o = new Option();
				o.setCode(code);
				o.setLevel(level);
				o.setName(name);
				o.setParentCode(parentCode);
				o.setSort(sort);
				o.setType(type);
				o.setUrl(url);
				
				thirdList.add(o);
		    }
		}  
		return thirdList;
	}

	/**
	 * 插入二级Option
	 * @return
	 */
	private List<Option> getSecondAndThirdLevelOption() {
		// 以二级Option为key，对应Controller中的Method[]为value
		Map<Option, Method[]> classMethodMap = new HashMap<Option, Method[]>(); 
		
		// 二级
		List<Option> secondList = new ArrayList<Option>();
		// 从Spring factory获取所有的Controller
		Map<String, Object> action = appContext.getBeansWithAnnotation(Controller.class);
		Collection<Object> ctrls = action.values();
		// 遍历@SubModuleName注解的Controller
		for (Object c : ctrls) {
			Class<? extends Object> clazz = c.getClass();
			
			if(!clazz.isAnnotationPresent(RequestMapping.class)) {
				continue;
			}
			if(!clazz.isAnnotationPresent(SubModuleName.class)) {
				logger.warn("注意::::" + clazz.getName() + "没有加上@SubModuleName，此类下面URL将不被保存到权限库");
				continue;
			}
			
			RequestMapping rm = (RequestMapping) clazz.getAnnotation(RequestMapping.class);
			SubModuleName sn = (SubModuleName) clazz.getAnnotation(SubModuleName.class);
			
			String name = sn.value();
			String parentCode = sn.root().toString();
			Integer sort = sn.sort();
			Integer level = 2;
			String url = rm.value()[0];
			String code = parentCode.concat("-").concat(url.replaceFirst("/", ""));
			String type = "CLASS";
			
			Option o = new Option();
			o.setCode(code);
			o.setLevel(level);
			o.setName(name);
			o.setParentCode(parentCode);
			o.setSort(sort);
			o.setType(type);
			o.setUrl(url);
			
			secondList.add(o);
			
			Method[] mths = clazz.getMethods();
			classMethodMap.put(o, mths);
		}
		
		List<Option> third = getThirdLevelOption(classMethodMap);
		secondList.addAll(third);
		return secondList;
	}

	/**
	 * 插入一级
	 * @return 
	 */
	private List<Option> getFirstLevelOption() {
		// 一级
		List<Option> firstList = new ArrayList<Option>();
		/*遍历Group*/
		for (Module m : Module.values()) {
			if (!"none".equals(m.toString())) {
				Option o = new Option();
				o.setCode(m.toString());
				o.setName(m.getName());
				o.setParentCode("0");
				o.setSort(m.getSort());
				o.setLevel(1);
				firstList.add(o); //第一级URL
			}
		}
		return firstList;
	}
	
}
